<?php

/**
 * Project form base class.
 *
 * @package    cybero
 * @subpackage form
 * @version 1.0   Добавлен метод trim для всех string полей.
 * @version 1.1   Добавлен метод doSave() для совместимости с nlPrimaryKeyHelper::renamePrimaryKey();
 * @version 1.2   Исправлены ошибки если главный ключ был unsetнут
 * @version 1.3   Relation Bugfix
 * @version 1.4   Не переопределяется валидатор на nlValidatorNumber. Выделение текста при получении фокуса и очистка при потере
 * @version 1.5   Опции для nlValidatorNumber
 * 
 * @author     Nitra Labs
 * @version    SVN: $Id: BaseFormDoctrine.class.php 167 2011-07-22 10:08:14Z sasha $
 */
abstract class BaseFormDoctrine extends sfFormDoctrine {

    public function setup() {

        unset($this['created_at']);
        unset($this['updated_at']);
        unset($this['created_by']);
        unset($this['updated_by']);
        unset($this['deleted_at']);
        unset($this['item_type']);

// Заменяем валидаторы для дробных значений чтоб могли воспринимать запятую
        foreach ($this->getValidatorSchema()->getFields() as $field => $validator) {
            if (get_class($validator) == 'sfValidatorNumber') {
                $options = $this->validatorSchema[$field]->getOptions();
                $this->validatorSchema[$field] = new nlValidatorNumber();
                $this->validatorSchema[$field]->setOptions($options);
            }
        }

        foreach ($this->getWidgetSchema()->getFields() as $field => $widget) {
            // Настройка виджетов для вывода валидации на клиенте, если есть соот. валидация на сервере.
            // $field - название виджета
            // Идея: для каждого виджета добавляем соответсвующий атрибут
            $options = $this->getObject()->getTable()->getDefinitionOf($field);

            if (get_class($widget) == 'sfWidgetFormInputText') {
                // Исключаем пробелы в начале и кноце строк
                $this->validatorSchema[$field]->setOption('trim', true);
                // При получении фокуса выделяем текст
                $widget->setAttribute('onFocus', 'this.select();');
                // При потере фокуса очищаем выделение
                $widget->setAttribute('onBlur', "this.value +=' '; this.value = this.value.slice(0, -1);");
                // Обязателен ввод данных в поле ввода
                if (isset($options['notnull']) && $options['notnull'] == true) {
                    $widget->setAttribute('required', 'required');
                }

                switch ($options['type']) {
                    case 'string':
                        if (isset($options['length']) && $options['length']) {
                            $widget->setAttribute('pattern', '^.{0,' . $options['length'] . '}$');
                            $this->validatorSchema[$field]->setOption('max_length', $options['length']);
                        }
                        break;

                    case 'integer':
                        $min = 0;
                        $max = 0;

                        if (isset($options['unsigned']) && $options['unsigned'] == true) {
                            switch ($options['length']) {
                                case 1:
                                    $min = 0;
                                    $max = 255;
                                    break;
                                case 2:
                                    $min = 0;
                                    $max = 65535;
                                    break;
                                case 3:
                                    $min = 0;
                                    $max = 16777215;
                                    break;
                                case 4:
                                    $min = 0;
                                    $max = 4294967295;
                                    break;
                                case 5:
                                default:
                                    $min = 0;
                                    $max = 18446744073709551615;
                                    break;
                            }

                            $widget->setAttribute('pattern', '^\d+$');
                        } else {
                            switch ($options['length']) {
                                case 1:
                                    $min = -128;
                                    $max = 127;
                                    break;
                                case 2:
                                    $min = -32768;
                                    $max = 32767;
                                    break;
                                case 3:
                                    $min = -8388608;
                                    $max = 8388607;
                                    break;
                                case 4:
                                    $min = -2147483648;
                                    $max = 2147483647;
                                    break;
                                case 5:
                                default:
                                    $min = -9223372036854775808;
                                    $max = 9223372036854775807;
                                    break;
                            }
                            $widget->setAttribute('pattern', '^-{0,1}\d+$');
                        }
                        $this->validatorSchema[$field]->setOption('min', $min);
                        $this->validatorSchema[$field]->setOption('max', $max);
                        break;

                    // case 'double': использует sfValidatorPass
                    case 'float':
                    case 'decimal':
                        if (isset($options['unsigned']) && $options['unsigned'] == true) {
                            $this->validatorSchema[$field]->setOption('min', 0);
                            if (isset($options['length']) && isset($options['scale'])) {
                                $this->validatorSchema[$field]->setOption('max', pow(10, $options['length'] - $options['scale']) - 1);
                                $widget->setAttribute('pattern', '\d{1,' . ($options['length'] - $options['scale']) . '}((,|\.)\d{1,' . $options['scale'] . '})?');
                            } else {
                                $widget->setAttribute('pattern', '\d+((,|\.)\d+)?');
                            }
                        } else {
                            if (isset($options['length']) && isset($options['scale'])) {
                                $this->validatorSchema[$field]->setOption('min', -1 * round(pow(10, $options['length'] - $options['scale'])) + 1);
                                $this->validatorSchema[$field]->setOption('max', round(pow(10, $options['length'] - $options['scale'])) - 1);
                                $widget->setAttribute('pattern', '-{0,1}\d{1,' . ($options['length'] - $options['scale']) . '}((,|\.)\d{1,' . $options['scale'] . '})?');
                            } else {
                                $widget->setAttribute('pattern', '-{0,1}\d+((,|\.)\d+)?');
                            }
                        }
                        break;
                }
                // Проверяем является ли ключем текстовое поле - и делаем его видимым для редактирования
            } elseif (get_class($widget) == 'sfWidgetFormInputHidden' && $options['type'] == 'string' && isset($options['primary']) && $options['primary']) {
                $widget->setAttribute('required', 'required');
                $this->validatorSchema[$field]->setOption('max_length', $options['length']);

                // Для уже созданных обьектов
                if (!$this->getObject()->isNew()) {
                    // Имеет ли обьект связи с другими классами
                    $rel_count = false;
                    foreach ($this->getObject()->getTable()->getRelations() as $relation) {
                        if ($relation instanceof Doctrine_Relation_ForeignKey && Doctrine_Query::create()->parseDqlQuery($relation->getRelationDql(1))->count($this->getObject()->getPrimaryKey())) {
                            $rel_count = true;
                            break;
                        }
                    }
                    // Задаем для обьекта аттрибут только на чтение, для не нарушения целостности БД
                    if ($rel_count)
                        $this->widgetSchema[$field]->setAttribute('readonly', 'readonly');
                }

                // Проверяем на уникальность первичный ключ с учетом SoftDelete
                $this->mergePostValidator(new sfValidatorCallback(array(
                            'callback' => array($this, 'validateStringId'),
                            'arguments' => $this->getObject()
                                ), array(
                            'invalid' => '%id% уже существует.'
                        )));
            }
            if (get_class($widget) == 'sfWidgetFormDate') {
                $this->widgetSchema[$field] = new nlWidgetFormHtml5Date();
            }
        }

        // Только Ртетрадка
        foreach ($this->widgetSchema as $name => $widget) {
            if ($widget instanceof sfWidgetFormDoctrineChoice && in_array($name, array('pov_id', 'product_option_value_id', 'product_id'))) {
                $this->widgetSchema[$name] = new sfWidgetFormInputHidden();
            }

            if ('order_id' === $name) {
                $this->widgetSchema[$name] = new sfWidgetFormInputText();
            }

            $this->widgetSchema[$name] = new sfWidgetFormInputHidden();

            if ($widget instanceof sfWidgetFormDate) {
                $this->widgetSchema[$name] = new nlWidgetFormHtml5Date($widget->getOptions(), $widget->getAttributes() + array('class' => 'date_relative'));
            }
            if ($widget instanceof sfWidgetFormDateTime) {
                $this->widgetSchema[$name] = new nlWidgetFormHtml5Date($widget->getOptions() + array('with_time' => true), $widget->getAttributes() + array('class' => 'date_relative'));
            }
        }
    }

    /**
     *
     *
     * @param <type> $validator
     * @param <type> $values
     * @param Doctrine_Record $object Обьект из таблицы базы данных,
     *  который нужно проверить на уникальность
     * @return <type>
     */
    public function validateStringId($validator, $values, Doctrine_Record $object) {
        // Первчиный ключ таблицы
        $primary = $object->getTable()->getIdentifier();

        // Если ключ составной, то не осуществляем проверку
        if (is_array($primary) || !isset($values[$primary]))
            return $values;

        $values[$primary] = trim($values[$primary]);

        // если обьект существует и название параметра не изменялось
        if ($object->exists() && $object->get($primary) == $values[$primary]) {
            return $values;
        }

        // Проверяем на уникальность
        if ($object->getTable()->find($values[$primary]))
            throw new sfValidatorError($validator, 'invalid', array($primary => $values[$primary]));

        // Если установлен SoftDelete то проверяем на удаленные
        if ($object->getTable()->hasTemplate('Doctrine_Template_SoftDelete')) {
            $softDelete = $object->getTable()->getTemplate('Doctrine_Template_SoftDelete');

            $is_deleted = (bool) $object->getTable()->createQuery('id')
                            ->where($primary . ' = ?', $values[$primary])
                            ->andWhere('id.' . $softDelete->getOption('name') . ' IS NOT NULL')
                            ->count();

            if ($is_deleted)
                throw new sfValidatorError($validator, 'invalid', array($primary => 'Такая запись находится в списке с удаленными: ' . $values[$primary]));
        }

        return $values;
    }

    protected function doSave($con = null) {
        $ids = $this->getObject()->identifier();
        if (isset($values[key($ids)]) && !$this->isNew && $this->getObject()->{key($ids)} !== $this->values[key($ids)]) {
            nlPrimaryKeyHelper::renamePrimaryKey($this->getModelName(), $this->getObject()->{key($ids)}, $this->values[key($ids)]);
        } else {
            parent::doSave();
        }
    }

}
